package com.mall.shopping.services;

import com.fasterxml.jackson.databind.ObjectMapper;
import com.mall.commons.doc.ItemDoc;
import com.mall.commons.tool.utils.ObjectIsEmptyUtils;
import com.mall.shopping.ISearchService;
import com.mall.shopping.constants.ShoppingRetCode;
import com.mall.shopping.dto.*;
import org.apache.dubbo.config.annotation.Service;
import org.elasticsearch.action.search.SearchRequest;
import org.elasticsearch.action.search.SearchResponse;
import org.elasticsearch.client.RequestOptions;
import org.elasticsearch.client.RestHighLevelClient;
import org.elasticsearch.index.query.QueryBuilders;
import org.elasticsearch.search.SearchHit;
import org.elasticsearch.search.SearchHits;
import org.elasticsearch.search.sort.SortBuilders;
import org.elasticsearch.search.sort.SortOrder;
import org.elasticsearch.search.suggest.Suggest;
import org.elasticsearch.search.suggest.SuggestBuilder;
import org.elasticsearch.search.suggest.SuggestBuilders;
import org.elasticsearch.search.suggest.completion.CompletionSuggestion;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;

import java.io.IOException;
import java.util.ArrayList;
import java.util.List;

/**
 * 类<code>Doc</code>用于：TODO
 *
 * @author Acher
 * @version 1.0
 * @date 2021-11-02
 */
//@Component
@Service
public class ISearchServiceImpl implements ISearchService {

    @Autowired
    RestHighLevelClient client;

    @Override
    public SearchCompleteResponse searchComplete(SearchCompleteRequest req) {
        SearchCompleteResponse resp = new SearchCompleteResponse();
        try {
            req.requestCheck();
            // 1.准备Request
            SearchRequest request = new SearchRequest("goods");
            // 2.准备DSL，核心api：source(),QueryBuilders
            String name = "suggestions";
            request.source().suggest(new SuggestBuilder()
                    .addSuggestion(name, SuggestBuilders
                            .completionSuggestion("suggestion")
                            .prefix(req.getKeyword())
                            .skipDuplicates(true)
                            .size(10)
                    ));
            // 3.发送
            SearchResponse searchResponse = client.search(request, RequestOptions.DEFAULT);
            // 4.处理结果
            Suggest suggest = searchResponse.getSuggest();
            // 4.1.根据名称获取补全结果
            CompletionSuggestion suggestion = suggest.getSuggestion(name);
            // 4.2.获取option并遍历
            List<String> key = new ArrayList<>();
            suggestion.getOptions()
                    .forEach(option -> key.add(option.getText().string()));
            resp.setCode(ShoppingRetCode.SUCCESS.getCode());
            resp.setMsg(ShoppingRetCode.SUCCESS.getMessage());
            resp.setData(key);
        } catch (Exception e) {
            e.printStackTrace();
            resp.setCode(ShoppingRetCode.DB_EXCEPTION.getCode());
            resp.setMsg(ShoppingRetCode.DB_EXCEPTION.getMessage());
        }
        return resp;
    }

    @Override
    public SearchContentResponse search(SearchContentRequest req) {
        SearchContentResponse resp = new SearchContentResponse();
        try {
//            req.requestCheck();
            // 1.准备Request
            SearchRequest request = new SearchRequest("goods");
            SearchResponse searchResponse = getSearchResponse(req, request);
            // 4.处理结果
            SearchHits searchHits = searchResponse.getHits();
            long total = searchHits.getTotalHits();
            SearchHit[] hits = searchHits.getHits();
            ObjectMapper mapper = new ObjectMapper();
            List<ProductDto> productDtos = new ArrayList<>();
            List<ItemDoc> itemDocs = new ArrayList<>();
            for (SearchHit hit : hits) {
                String json = hit.getSourceAsString();
                itemDocs.add(mapper.readValue(json, ItemDoc.class));
            }
            itemDocs.forEach(itemDoc -> productDtos.add(new ProductDto(itemDoc)));
            resp.setCode(ShoppingRetCode.SUCCESS.getCode());
            resp.setMsg(ShoppingRetCode.SUCCESS.getMessage());
            resp.setTotal(total);
            resp.setData(productDtos);
        } catch (Exception e) {
            e.printStackTrace();
            resp.setCode(ShoppingRetCode.DB_EXCEPTION.getCode());
            resp.setMsg(ShoppingRetCode.DB_EXCEPTION.getMessage());
        }
        return resp;
    }

    private SearchResponse getSearchResponse(SearchContentRequest req, SearchRequest request) throws IOException {
        // 2.准备DSL，核心api：source(),QueryBuilders
        if (ObjectIsEmptyUtils.stringIsEmpty(req.getKey())) {
            request.source().query(QueryBuilders.matchAllQuery());
        } else {
            request.source().query(QueryBuilders.matchQuery("all", req.getKey()));
        }
        if (!ObjectIsEmptyUtils.stringIsEmpty(req.getPriceLte()) && !ObjectIsEmptyUtils.stringIsEmpty(req.getPriceGt())) {
            request.source()
                    .query(QueryBuilders.boolQuery()
                            .filter(QueryBuilders.rangeQuery("price")
                                    .gte(req.getPriceGt())
                                    .lte(req.getPriceLte())));
        } else if (!ObjectIsEmptyUtils.stringIsEmpty(req.getPriceLte())) {
            request.source()
                    .query(QueryBuilders.boolQuery()
                            .filter(QueryBuilders.rangeQuery("price")
                                    .lte(req.getPriceLte())));
        } else if (!ObjectIsEmptyUtils.stringIsEmpty(req.getPriceGt())) {
            request.source()
                    .query(QueryBuilders.boolQuery()
                            .filter(QueryBuilders.rangeQuery("price")
                                    .gte(req.getPriceGt())));
        }
        if (!ObjectIsEmptyUtils.stringIsEmpty(req.getSort())) {
            if (Integer.parseInt(req.getSort()) == 1) {
                request.source().sort("price");
            } else if (Integer.parseInt(req.getSort()) == -1) {
                request.source().sort("price", SortOrder.DESC);
            }
        }
        request.source()
                .from((req.getPage() - 1) * req.getSize())
                .size(req.getSize());
        // 3.发送
        SearchResponse searchResponse = client.search(request, RequestOptions.DEFAULT);
        return searchResponse;
    }
}
